<script setup>
import { onMounted, onUnmounted, ref } from "vue";
import { Download, Plus, Upload } from "@element-plus/icons-vue";
import { read as excelRead, utils as excelUtils } from "xlsx";

import DeviceDetail from "./components/DeviceDetail.vue";
import PointTable from "./components/PointTable.vue";
import DeviceCard from "./components/DeviceCard.vue";
import PreAddPointTable from "./components/PreAddPointTable.vue";
import { getDevices, deleteDevice, downloadPointsExcel } from "@/api/device";
import { DeviceRealTime } from "@/api/ws";
import NothingPage from "@/assets/imgs/nothing.png";
import NoRecord from "@/assets/imgs/norecord.png";

const devices = ref([])

function toGetDevices() {
  getDevices().then(res => {
    if (res.code === 200) {
      devices.value = res.data
    } else {
      ElMessage.error(res.msg)
    }
  }).catch(err => {
    console.log(err)
    ElMessage.error("网络异常，请稍后重试")
  })
}
toGetDevices()

const selectedDevice = ref()

const detailVisible = ref(false)

function toCreateDevice() {
  selectedDevice.value = null
  detailVisible.value = true
}

function toReadDevice(no) {
  selectedDevice.value = no
  detailVisible.value = true
}

function toDeleteDevice(no) {
  ElMessageBox.confirm("确认删除该设备吗？", "警告", {
    type: "warning",
    confirmButtonText: "确定",
    cancelButtonText: "取消"
  }).then(() => {
    deleteDevice(no).then(res => {
      if (res.code === 200) {
        ElMessage.success("删除成功")
        toGetDevices()
      } else {
        ElMessage.error(res.msg)
      }
    }).catch(err => {
      console.log(err)
      ElMessage.error("网络异常，请稍后重试")
    })
  }).catch(() => {})
}

// 设备点位批量上传
const fileList = ref([])
const filePoints = ref([])

function readExcel(file) {
  const reader = new FileReader()
  reader.onload = (e) => {
    const data = reader.result
    const wb = excelRead(data, { type: 'buffer' })
    const result = []
    wb.SheetNames.forEach(name => {
      const obj = {
        deviceNo: name,
        points: excelUtils.sheet_to_json(
          wb.Sheets[name],
          { header: ["group", "name", "desc", "func", "addr"] }
        )
      }
      // 去除表头的中文提示
      if (obj.points.length > 0) {
        obj.points.splice(0, 1)
      }
      result.push(obj)
    })
    filePoints.value = result
    preAddTableVisible.value = true
  }
  reader.onerror = (err) => {
    console.log(err)
  }
  reader.readAsArrayBuffer(file);
}

function toUploadFile({ file }) {
  const fileType = file.name.substring(file.name.lastIndexOf('.') + 1);
  if (fileType !== 'xls' && fileType !== 'xlsx') {
      ElMessage.error('请上传正确的Excel文件（文件类型应为xls或xlsx）');
    } else {
      readExcel(file); // 读取文件内容
    }
}

// 预添加点位对话框显示
const preAddTableVisible = ref(false)

function toPreAddPoints() {
  preAddTableVisible.value = true
}

// 定时监听设备状态
// 创建ws实例用于实时获取点位值
let devCom
// 用户需要查看日志的设备
const logDev = ref()
// 选中设备的异常日志
const logs = ref([])
const logVisible = ref(false)

function toReadLog(deviceNo) {
  logDev.value = deviceNo
  logVisible.value = true
}

onMounted(() => {
  const sendMsg = () => {
    if (devices.value && devices.value.length > 0) {
      devCom.send({ devices: devices.value.map(d => d.no), logDev: logDev.value })
    } else {
      setTimeout(sendMsg, 500)
    }
  }
  devCom = DeviceRealTime(
    (msg) => {
      for (let i = 0; i < devices.value.length; i++) {
        const dev = devices.value[i]
        const newStatus = msg.status[dev.no]
        logs.value = msg.logs
        if (newStatus) dev.status = newStatus
        else dev.status = 3
      }
      setTimeout(sendMsg, 500)
    }, 
    sendMsg,
    () => {
      for (let i = 0; i < devices.value.length; i++) {
        const dev = devices.value[i]
        dev.status = 4
      }
    }
  )
})

onUnmounted(() => {
  devCom.close()
})
</script>

<template>
  <el-card class="devs-box">
    <template #header>
      <div class="devs-header">
        <div class="title">设备列表</div>
        <div class="extra">
          <el-button text type="primary" :icon="Download" @click="downloadPointsExcel()">导出点位</el-button>
          <el-upload 
            v-model:file-list="fileList" 
            action="/" accept=".xls,.xlsx"
            :show-file-list="false"
            :http-request="toUploadFile"
          >
            <template #trigger>
              <el-button text type="primary" :icon="Upload">批量导入</el-button>
            </template>
          </el-upload>
          <el-button
            text type="primary" :icon="Plus"
            @click="toCreateDevice"
          >添加设备</el-button>
        </div>
      </div>
    </template>
    <el-row :gutter="20" v-if="devices.length > 0">
      <el-col 
        v-for="dev in devices" :key="dev.no"
        :xl="6" :lg="8" :md="12" :sm="24" :xs="24"
      >
        <device-card
          :data="dev"
          :status="dev.status"
          @click="selectedDevice = dev.no"
          @dblclick="toReadDevice(dev.no)"
          @close-click="toDeleteDevice(dev.no)"
          @read-log="toReadLog(dev.no)"
          :selected="selectedDevice === dev.no"
          style="margin-bottom: 12px;"
        />
      </el-col>
    </el-row>
    <el-empty v-else :image="NothingPage">
      <template #description>
        查无设备信息哦，你可以先
        <el-button link type="primary" @click="toCreateDevice">点击此处</el-button>
        或右上角添加设备
      </template>
    </el-empty>
    <device-detail
      :no="selectedDevice"
      v-model:visible="detailVisible" 
      @submit="toGetDevices()"
    />
  </el-card>
  <point-table v-if="devices.length > 0" :no="selectedDevice" />
  <pre-add-point-table 
    v-model:visible="preAddTableVisible" 
    :data="filePoints"
    @update="selectedDevice = null"
  />
  <el-dialog v-model="logVisible" :title="`设备${logDev}的异常日志`">
    <el-scrollbar v-if="logs && logs.length > 0" height="640">
      <el-card class="log-card" v-for="log in logs">
        <div>{{ log.time }}</div>
        <div>{{ log.content }}</div>
      </el-card>
    </el-scrollbar>
    <el-empty v-else :image="NoRecord" description="该设备暂无已知的通讯异常" />
  </el-dialog>
</template>

<style lang="scss" scoped>
.devs-box {
  margin-bottom: 24px;
}
.devs-header {
  display: flex;
  justify-content: space-between;
  .extra {
    display: flex;
    justify-content: center;
  }
}
.log-card {
  margin-bottom: 12px;
}
</style>
